package com.varteq.progress.server;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.varteq.progress.shared.ProgressChangeEvent;

public final class Progress {
	private static final int EVENT_WAIT = 1000;

	private static final HashMap<String, Progress> _progressMap = new HashMap<String, Progress>();

	private final String _name;
	private final List<ProgressChangeEvent> _events = new ArrayList<ProgressChangeEvent>();

	private boolean _complete;

	private Progress(String name) {
		_name = name;
	}

	private synchronized void addEvent(ProgressChangeEvent event) {
		if (!_complete) {
			_events.add(event);
			_complete = event.isComplete();
			notifyAll();
		}
	}

	public synchronized void addEvent(String description, Double percentage, boolean complete, Serializable data) {
		addEvent(new ProgressChangeEvent(description, percentage, complete, data));
	}

	public boolean isComplete() {
		return _complete;
	}

	private List<ProgressChangeEvent> getEventsAfterWait() {
		if (!_complete && _events.isEmpty()) {
			try {
				synchronized (this) {
					wait(EVENT_WAIT);
				}
			} catch (final InterruptedException ie) {
				ie.printStackTrace();
			}
		}
		return getEventsAndClear();
	}

	private synchronized List<ProgressChangeEvent> getEventsAndClear() {
		ArrayList<ProgressChangeEvent> result = new ArrayList<ProgressChangeEvent>(_events);
		_events.clear();
		return result;
	}

	public String getName() {
		return _name;
	}

	public synchronized static Progress createProgress(String progressName) {
		Progress progress = new Progress(progressName);
		_progressMap.put(progressName, progress);
		return progress;
	}

	public synchronized static Progress getProgress(String progressName) {
		return _progressMap.get(progressName);
	}

	public synchronized static Progress removeProgress(String progressName) {
		return _progressMap.remove(progressName);
	}

	public static List<ProgressChangeEvent> getProgressEvents(String progressName) {
		Progress progress = getProgress(progressName);
		if (progress != null) {
			if (progress.isComplete()) {
				removeProgress(progressName);
			}
			List<ProgressChangeEvent> result = progress.getEventsAfterWait();
			return result;
		} else {
			return null;
		}
	}
}
